﻿using An_Im.Core;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using PPT = Microsoft.Office.Interop.PowerPoint;
using An_Im.CoreManipulatorUtil;

namespace An_Im
{
    /// <summary>
    /// 核心的控制者
    /// </summary>
    static partial class CoreManipulator
    {
        /// <summary>
        /// 文件夹路径。
        /// </summary>
        public static string FolderPath => Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "An_Im");


        /// <summary>
        /// 自定义动画导出路径。
        /// </summary>
        public static string CustomAnimationExportPath => Path.Combine(FolderPath, "Custom");

        /// <summary>
        /// 文件存档路径。
        /// </summary>
        public static string SavePath => Path.Combine(FolderPath, "save.xml");

        /// <summary>
        /// 动画重命名路径。
        /// </summary>
        public static string RenamedAnimationEffectConfigPath => Path.Combine(FolderPath, "RenamedAnimationEffectConfig.xml");

        /// <summary>
        /// 插件拓展项位置。
        /// </summary>
        public static string AddInStorePath => Path.Combine(FolderPath, "Extensions");

        /// <summary>
        /// 应用配置文件。
        /// </summary>
        public static string TaskPaneConfig=> Path.Combine(FolderPath, "TaskPaneConfig.xml");


        /// <summary>
        /// PPT的顶层程序。
        /// </summary>
        internal static PPT.Application App => Globals.ThisAddIn.Application;

        #region 删除动画

        /// <summary>
        /// 删除附在指定图形上的指定动画。
        /// </summary>
        /// <param name="shape"></param>
        private static void DeleteAllAnimationsAttachedShape(PPT.Shape shape)
        {
            var slide = GetSlideInGeneralOccassion();
            if (slide == null || shape == null) return;
            if (slide.TimeLine.MainSequence.Count == 0) return;
            int count = slide.TimeLine.MainSequence.Count;

            for (int i = count; i >= 1; i--)
            {
                var eff = slide.TimeLine.MainSequence[i];
                if (eff.Shape == shape)
                    eff.Delete();
            }
        }


        /// <summary>
        /// 删除附在指定图形上的指定动画。
        /// </summary>
        /// <param name="shape"></param>
        private static void DeleteAllAnimationsAttachedShapeRange(PPT.ShapeRange shapeRange)
        {
            if (shapeRange == null) return;
            foreach (PPT.Shape shape in shapeRange)
            {
                DeleteAllAnimationsAttachedShape(shape);
            }

        }

        /// <summary>
        /// 删除所有附加在图形集合上的动画。
        /// </summary>
        public static void DeleteAllAnimationsAttachedShapeRange()
        {
            DeleteAllAnimationsAttachedShapeRange(GetShapeRange());
            GlobalMessageStateUpdater.RaiseAnimationSequenceMessage();
        }
        #endregion

        #region 录制动画

        /// <summary>
        /// 录制人工效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static string RecordArtificialEffect(PPT.Effect eff, string tags)
        {
            var sb = new StringBuilder();

            var shp = eff.Shape;
            var tim = eff.Timing;

            var timing = GetTimeDetail(tim);

            sb.AppendFormat(Properties.Resources.EffectNode1,
                shp.Name.Trim().Replace(' ', '_'),
                tags,
                shp.TextEffect.Text,
                timing,
                shp.AnimationSettings.TextUnitEffect);
            sb.AppendLine();

            foreach (PPT.AnimationBehavior behavior in eff.Behaviors)
            {
                var btim = behavior.Timing;
                var btiming = GetTimeDetail(btim);

                switch (behavior.Type)
                {
                    case PPT.MsoAnimType.msoAnimTypeMotion:
                        sb.AppendFormat(Properties.Resources.MotionNode,
                            typedic1[behavior.Type],
                           btiming,
                            behavior.MotionEffect.FromX,
                            behavior.MotionEffect.FromY,
                            behavior.MotionEffect.ToX,
                            behavior.MotionEffect.ToY,
                            behavior.MotionEffect.ByX,
                            behavior.MotionEffect.ByY,
                            behavior.MotionEffect.Path);
                        sb.AppendLine();
                        break;
                    case PPT.MsoAnimType.msoAnimTypeColor:
                        throw new Exception("颜色相关处理暂时无效。");
                        sb.AppendFormat(Properties.Resources.ColorNode,
                            typedic1[behavior.Type],
                             btiming,
                            behavior.ColorEffect.From.RGB,
                            behavior.ColorEffect.To.RGB,
                            behavior.ColorEffect.By.RGB);
                        sb.AppendLine();
                        break;
                    case PPT.MsoAnimType.msoAnimTypeScale:
                        sb.AppendFormat(Properties.Resources.ScaleNode,
                            typedic1[behavior.Type],
                            btiming,
                            behavior.ScaleEffect.FromX,
                            behavior.ScaleEffect.FromY,
                            behavior.ScaleEffect.ToX,
                            behavior.ScaleEffect.ToY,
                            behavior.ScaleEffect.ByX,
                            behavior.ScaleEffect.ByY);
                        sb.AppendLine();
                        break;
                    case PPT.MsoAnimType.msoAnimTypeRotation:
                        sb.AppendFormat(Properties.Resources.RotationNode,
                            typedic1[behavior.Type],
                           btiming,
                            behavior.RotationEffect.From,
                            behavior.RotationEffect.To,
                            behavior.RotationEffect.By);
                        sb.AppendLine();
                        break;
                    case PPT.MsoAnimType.msoAnimTypeProperty:
                        sb.AppendFormat(Properties.Resources.PropNode1,
                           typedic1[behavior.Type],
                           btiming,
                           propdic1[behavior.PropertyEffect.Property],
                           behavior.PropertyEffect.From,
                           behavior.PropertyEffect.To);
                        foreach (PPT.AnimationPoint point in behavior.PropertyEffect.Points)
                        {
                            sb.AppendFormat(Properties.Resources.PointNode,
                                point.Time,
                                point.Value,
                                point.Formula);

                            sb.AppendLine();
                        }
                        sb.AppendFormat(Properties.Resources.PropNode2);
                        sb.AppendLine();
                        break;
                    case PPT.MsoAnimType.msoAnimTypeFilter:
                        string subtype = "none";
                        try
                        {
                            subtype = ((int)behavior.FilterEffect.Subtype).ToString();
                        }
                        catch { }
                        sb.AppendFormat(Properties.Resources.FilterNode,
                            typedic1[behavior.Type],
                            btiming,
                            behavior.FilterEffect.Reveal,
                            behavior.FilterEffect.Type,
                            subtype);
                        sb.AppendLine();

                        break;
                    case PPT.MsoAnimType.msoAnimTypeSet:
                        sb.AppendFormat(Properties.Resources.SetNode,
                            typedic1[behavior.Type],
                            btiming,
                            propdic1[behavior.SetEffect.Property],
                            behavior.SetEffect.To);
                        sb.AppendLine();

                        break;
                    default:
                        break;
                }
            }
            sb.AppendFormat(Properties.Resources.EffectNode2);
            sb.AppendLine();
            sb.AppendLine();
            return sb.ToString();
        }

        /// <summary>
        /// 录制原生效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static string RecordNativeEffect(PPT.Effect eff, string tags)
        {
            var sb = new StringBuilder();

            var shp = eff.Shape;
            var tim = eff.Timing;
            var sb2 = new StringBuilder();

            var btiming = GetTimeDetail(tim);

            if (eff.EffectType == PPT.MsoAnimEffect.msoAnimEffectSpin)
            {
                sb2.Append(eff.Behaviors[1].RotationEffect.By);
            }
            else if (eff.EffectType == PPT.MsoAnimEffect.msoAnimEffectGrowShrink)
            {
                sb2.Append(eff.Behaviors[1].ScaleEffect.ByX); sb2.Append(",");
                sb2.Append(eff.Behaviors[1].ScaleEffect.ByY);
            }
            else if ((int)eff.EffectType >= (int)PPT.MsoAnimEffect.msoAnimEffectPathCircle)
            {
                sb2.Append(eff.Behaviors[1].MotionEffect.Path);
            }

            sb.AppendFormat(Properties.Resources.NativeEffectNode1,
                shp.Name.Trim().Replace(' ', '_'),
                tags,
                shp.TextEffect.Text,
               btiming,
                eff.EffectType,
                eff.Exit, sb2,
                shp.AnimationSettings.TextUnitEffect);

            sb.AppendLine();
            sb.AppendFormat(Properties.Resources.NativeEffectNode2);
            sb.AppendLine();
            sb.AppendLine();
            return sb.ToString();
        }


        public static GroupEffectInformation RecordGroupEffect(IEnumerable<EffectInformation> effs, string name, IList<string> tags, string description)
        {
            var effectInfo = new GroupEffectInformation();
            effectInfo.Name = name;
            effectInfo.Tags = tags;
            effectInfo.Note = description;
            var list = new List<EffectInformation>();
            list.AddRange(effs);
            effectInfo.EffectInformationList = list;
            return effectInfo;
        }


        /// <summary>
        /// 录制人工效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static ArtificialEffectInformation RecordArtificialEffect(PPT.Effect eff, string name, IList<string> tags, string description)
        {

            var effectInfo = new ArtificialEffectInformation();
            var tim = eff.Timing;

            effectInfo.Name = name;
            effectInfo.Tags = tags;
            effectInfo.Note = description;
            SetTimeDetail(effectInfo, tim);
            effectInfo.TextUnitEffect = eff.EffectInformation.TextUnitEffect;

            effectInfo.BehaviorInformationList = new List<BehaviorInformation>();

            foreach (PPT.AnimationBehavior behavior in eff.Behaviors)
            {
                BehaviorInformation behaviorInfo = null;

                var btim = behavior.Timing;

                switch (behavior.Type)
                {
                    case PPT.MsoAnimType.msoAnimTypeMotion:
                        behaviorInfo = new MotionBehaviorInformation()
                        {
                            FromX = behavior.MotionEffect.FromX,
                            FromY = behavior.MotionEffect.FromY,
                            ToX = behavior.MotionEffect.ToX,
                            ToY = behavior.MotionEffect.ToY,
                            ByX = behavior.MotionEffect.ByX,
                            ByY = behavior.MotionEffect.ByY,
                            Path = behavior.MotionEffect.Path
                        };
                        break;
                    case PPT.MsoAnimType.msoAnimTypeColor:
                        throw new Exception("颜色相关处理暂时无效。");
                        behaviorInfo = new ColorBehaviorInformation()
                        {
                            From = behavior.ColorEffect.From.RGB,
                            To = behavior.ColorEffect.To.RGB,
                            By = behavior.ColorEffect.By.RGB
                        };

                        break;
                    case PPT.MsoAnimType.msoAnimTypeScale:
                        behaviorInfo = new ScaleBehaviorInformation()
                        {
                            FromX = behavior.ScaleEffect.FromX,
                            FromY = behavior.ScaleEffect.FromY,
                            ToX = behavior.ScaleEffect.ToX,
                            ToY = behavior.ScaleEffect.ToY,
                            ByX = behavior.ScaleEffect.ByX,
                            ByY = behavior.ScaleEffect.ByY
                        };

                        break;
                    case PPT.MsoAnimType.msoAnimTypeRotation:
                        behaviorInfo = new RotationBehaviorInformation()
                        {
                            From = behavior.RotationEffect.From,
                            To = behavior.RotationEffect.To,
                            By = behavior.RotationEffect.By
                        };

                        break;
                    case PPT.MsoAnimType.msoAnimTypeProperty:
                        behaviorInfo = new PropertyBehaviorInformation()
                        {

                            Property = behavior.PropertyEffect.Property,
                            From = behavior.PropertyEffect.From,
                            To = behavior.PropertyEffect.To,
                            KeyPoints = new List<KeyPointInformation>()
                        };

                        foreach (PPT.AnimationPoint point in behavior.PropertyEffect.Points)
                        {
                            (behaviorInfo as PropertyBehaviorInformation).KeyPoints.Add(new KeyPointInformation()
                            {
                                Time = point.Time,
                                Value = point.Value,
                                Formula = point.Formula
                            });

                        }

                        break;
                    case PPT.MsoAnimType.msoAnimTypeFilter:
                        PPT.MsoAnimFilterEffectSubtype? subtype = null;
                        try
                        {
                            subtype = behavior.FilterEffect.Subtype;
                        }
                        catch { }

                        behaviorInfo = new FilterBehaviorInformation()
                        {
                            Reveal = behavior.FilterEffect.Reveal,
                            MainFilter = behavior.FilterEffect.Type,
                            SubFilter = subtype
                        };
                        break;
                    case PPT.MsoAnimType.msoAnimTypeSet:
                        behaviorInfo = new SetBehaviorInformation()
                        {
                            Property = behavior.SetEffect.Property,
                            Value = behavior.SetEffect.To
                        };

                        break;
                    default:
                        throw new Exception("Command 和 None 型行为暂时无法处理。");
                }

                SetTimeDetail(behaviorInfo, btim);
                effectInfo.BehaviorInformationList.Add(behaviorInfo);

            }
            return effectInfo;
        }



        /// <summary>
        /// 录制原生效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static NativeEffectInformation RecordNativeEffect(PPT.Effect eff, string name, IList<string> tags, string description)
        {
            var effectInfo = new NativeEffectInformation();
            var tim = eff.Timing;
            effectInfo.Arguments = null;
            if (eff.EffectType == PPT.MsoAnimEffect.msoAnimEffectSpin)
            {
                effectInfo.Arguments = new string[] { eff.Behaviors[1].RotationEffect.By.ToString() };
            }

            else if (eff.EffectType == PPT.MsoAnimEffect.msoAnimEffectGrowShrink)
            {
                effectInfo.Arguments = new string[] {
                    $"{eff.Behaviors[1].ScaleEffect.ByX}",
                    $"{eff.Behaviors[1].ScaleEffect.ByY}" };

            }
            else if ((int)eff.EffectType >= (int)PPT.MsoAnimEffect.msoAnimEffectPathCircle)
            {
                effectInfo.Arguments = new string[] { eff.Behaviors[1].MotionEffect.Path };
            }
            effectInfo.Name = name;
            effectInfo.Tags = tags;
            effectInfo.Note = description;
            effectInfo.AnimEffect = eff.EffectType;
            effectInfo.Exit = eff.Exit;
            effectInfo.TextUnitEffect = eff.EffectInformation.TextUnitEffect;
            SetTimeDetail(effectInfo, tim);

            return effectInfo;
        }

        public static string ExportEffect(EffectInformation eff)
        {
            if (eff is ArtificialEffectInformation)
            {
                return ExportArtificialEffect(eff as ArtificialEffectInformation);
            }
            else if (eff is NativeEffectInformation)
            {
                return ExportNativeEffect(eff as NativeEffectInformation);
            }
            else if (eff is GroupEffectInformation)
            {
                return ExportGroupEffect(eff as GroupEffectInformation);
            }
            return null;
        }

        public static string ExportGroupEffect(GroupEffectInformation effinfo)
        {
            var sb = new StringBuilder();
            sb.AppendFormat(Properties.Resources.GroupNode1,
                effinfo.Name,
                effinfo.Tags != null ? string.Join(",", effinfo.Tags) : null,
                effinfo.Note);
            foreach (var eff in effinfo.EffectInformationList)
            {
                if (eff is ArtificialEffectInformation)
                {
                    sb.AppendLine(ExportArtificialEffect(eff as ArtificialEffectInformation));
                }
                else if (eff is NativeEffectInformation)
                {
                    sb.AppendLine(ExportNativeEffect(eff as NativeEffectInformation));
                }
                else if (eff is GroupEffectInformation)
                {
                    sb.AppendLine(ExportGroupEffect(eff as GroupEffectInformation));
                }
            }
            sb.AppendFormat(Properties.Resources.GroupNode2);
            sb.AppendLine();
            return sb.ToString();
        }


        /// <summary>
        /// 录制人工效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static string ExportArtificialEffect(ArtificialEffectInformation eff)
        {
            var sb = new StringBuilder();

            var timing = GetTimeDetail(eff);

            sb.AppendFormat(Properties.Resources.EffectNode1,
                eff.Name,
                eff.Tags != null ? string.Join(",", eff.Tags) : null,
                eff.Note,
                timing,
                eff.TextUnitEffect);
            sb.AppendLine();



            foreach (BehaviorInformation bhv in eff.BehaviorInformationList)
            {
                var btiming = GetTimeDetail(bhv);

                switch (bhv.AnimType)
                {
                    case PPT.MsoAnimType.msoAnimTypeMotion:
                        {
                            var behavior = bhv as MotionBehaviorInformation;
                            sb.AppendFormat(Properties.Resources.MotionNode,
                                typedic1[behavior.AnimType],
                               btiming,
                                behavior.FromX,
                                behavior.FromY,
                                behavior.ToX,
                                behavior.ToY,
                                behavior.ByX,
                                behavior.ByY,
                                behavior.Path);
                            sb.AppendLine();
                        }

                        break;
                    case PPT.MsoAnimType.msoAnimTypeColor:
                        {
                            throw new Exception("颜色相关处理暂时无效。");
                            var behavior = bhv as ColorBehaviorInformation;
                            sb.AppendFormat(Properties.Resources.ColorNode,
                                typedic1[behavior.AnimType],
                                btiming,
                                behavior.From,
                                behavior.To,
                                behavior.By);
                            sb.AppendLine();
                        }

                        break;
                    case PPT.MsoAnimType.msoAnimTypeScale:
                        {
                            var behavior = bhv as ScaleBehaviorInformation;
                            sb.AppendFormat(Properties.Resources.ScaleNode,
                                typedic1[behavior.AnimType],
                                btiming,
                                behavior.FromX,
                                behavior.FromY,
                                behavior.ToX,
                                behavior.ToY,
                                behavior.ByX,
                                behavior.ByY);
                            sb.AppendLine();
                        }
                        break;
                    case PPT.MsoAnimType.msoAnimTypeRotation:
                        {
                            var behavior = bhv as RotationBehaviorInformation;
                            sb.AppendFormat(Properties.Resources.RotationNode,
                                typedic1[behavior.AnimType],
                                btiming,
                                behavior.From,
                                behavior.To,
                                behavior.By);
                            sb.AppendLine();
                        }

                        break;
                    case PPT.MsoAnimType.msoAnimTypeProperty:
                        {
                            var behavior = bhv as PropertyBehaviorInformation;

                            sb.AppendFormat(Properties.Resources.PropNode1,
                               typedic1[behavior.AnimType],
                               btiming,
                               propdic1[behavior.Property.Value],
                               behavior.From,
                               behavior.To);
                            foreach (var point in behavior.KeyPoints)
                            {
                                sb.AppendFormat(Properties.Resources.PointNode,
                                    point.Time,
                                    point.Value,
                                    point.Formula);

                                sb.AppendLine();
                            }
                            sb.AppendFormat(Properties.Resources.PropNode2);
                            sb.AppendLine();
                        }
                        break;
                    case PPT.MsoAnimType.msoAnimTypeFilter:
                        {
                            var behavior = bhv as FilterBehaviorInformation;

                            sb.AppendFormat(Properties.Resources.FilterNode,
                                typedic1[behavior.AnimType],
                                btiming,
                                behavior.Reveal,
                                behavior.MainFilter,
                                behavior.SubFilter);
                            sb.AppendLine();
                        }
                        break;
                    case PPT.MsoAnimType.msoAnimTypeSet:
                        {
                            var behavior = bhv as SetBehaviorInformation;

                            sb.AppendFormat(Properties.Resources.SetNode,
                                typedic1[behavior.AnimType],
                                btiming,
                                propdic1[behavior.Property.Value],
                                behavior.Value);
                            sb.AppendLine();
                        }
                        break;
                    default:
                        break;
                }
            }
            sb.AppendFormat(Properties.Resources.EffectNode2);
            sb.AppendLine();
            sb.AppendLine();
            return sb.ToString();
        }

        /// <summary>
        /// 录制原生效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static string ExportNativeEffect(NativeEffectInformation eff)
        {
            var sb = new StringBuilder();
            var btiming = GetTimeDetail(eff);

            sb.AppendFormat(Properties.Resources.NativeEffectNode1,
                eff.Name,
                string.Join(",", eff.Tags),
                eff.Note,
                btiming,
                eff.AnimEffect,
                eff.Exit, string.Join(",", eff.Arguments),
                eff.TextUnitEffect);

            sb.AppendLine();
            sb.AppendFormat(Properties.Resources.NativeEffectNode2);
            sb.AppendLine();
            sb.AppendLine();
            return sb.ToString();
        }

        /// <summary>
        /// 录制原生效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static XmlElement ExportGroupEffect(XmlDocument xmldoc, GroupEffectInformation eff)
        {
            var xmlele = xmldoc.CreateElement("组动画效果"); // 创建元素

            xmlele.AddXmlAttribute("名称", eff.Name);
            if (eff.Tags == null) eff.Tags = new List<string>();
            xmlele.AddXmlAttribute("标签", string.Join(",", eff.Tags));
            xmlele.AddXmlAttribute("描述", eff.Note);

            foreach (var chieff in eff.EffectInformationList)
            {
                if (chieff is ArtificialEffectInformation)
                {
                    xmlele.AppendChild(ExportArtificialEffect(xmldoc, chieff as ArtificialEffectInformation));
                }
                else if (chieff is NativeEffectInformation)
                {
                    xmlele.AppendChild(ExportNativeEffect(xmldoc, chieff as NativeEffectInformation));
                }
                else if (chieff is GroupEffectInformation)
                {
                    xmlele.AppendChild(ExportGroupEffect(xmldoc, chieff as GroupEffectInformation));
                }
            }

            return xmlele;
        }

        /// <summary>
        /// 录制人工效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static XmlElement ExportArtificialEffect(XmlDocument xmldoc, ArtificialEffectInformation eff)
        {
            var xmlele = xmldoc.CreateElement("动画效果"); // 创建元素

            xmlele.AddXmlAttribute("名称", eff.Name);
            xmlele.AddXmlAttribute("标签", eff.Tags != null ? string.Join(",", eff.Tags) : "默认标签");
            xmlele.AddXmlAttribute("描述", eff.Note);

            SetTimeDetail(xmlele, eff);

            foreach (BehaviorInformation bhv in eff.BehaviorInformationList)
            {
                var bhvele = xmldoc.CreateElement(typedic1[bhv.AnimType]);
                bhvele.AddXmlAttribute("注释", "");
                SetTimeDetail(bhvele, bhv);

                switch (bhv.AnimType)
                {
                    case PPT.MsoAnimType.msoAnimTypeMotion:
                        {
                            var behavior = bhv as MotionBehaviorInformation;

                            bhvele.AddXmlAttribute("起点", $"{behavior.FromX},{behavior.FromY}");
                            bhvele.AddXmlAttribute("终点", $"{behavior.ToX},{behavior.ToY}");
                            bhvele.AddXmlAttribute("变化", $"{behavior.ByX},{behavior.ByY}");
                            bhvele.AddXmlAttribute("路径", behavior.Path);
                        }

                        break;
                    case PPT.MsoAnimType.msoAnimTypeColor:
                        {
                            throw new Exception("颜色相关处理暂时无效。");
                            var behavior = bhv as ColorBehaviorInformation;
                            bhvele.AddXmlAttribute("起点", $"{behavior.From}");
                            bhvele.AddXmlAttribute("终点", $"{behavior.To}");
                            bhvele.AddXmlAttribute("变化", $"{behavior.By}");
                        }

                        break;
                    case PPT.MsoAnimType.msoAnimTypeScale:
                        {
                            var behavior = bhv as ScaleBehaviorInformation;
                            bhvele.AddXmlAttribute("起点", $"{behavior.FromX},{behavior.FromY}");
                            bhvele.AddXmlAttribute("终点", $"{behavior.ToX},{behavior.ToY}");
                            bhvele.AddXmlAttribute("变化", $"{behavior.ByX},{behavior.ByY}");
                        }
                        break;
                    case PPT.MsoAnimType.msoAnimTypeRotation:
                        {
                            var behavior = bhv as RotationBehaviorInformation;

                            bhvele.AddXmlAttribute("起点", $"{behavior.From}");
                            bhvele.AddXmlAttribute("终点", $"{behavior.To}");
                            bhvele.AddXmlAttribute("变化", $"{behavior.By}");

                        }

                        break;
                    case PPT.MsoAnimType.msoAnimTypeProperty:
                        {
                            var behavior = bhv as PropertyBehaviorInformation;
                            bhvele.AddXmlAttribute("属性类型", propdic1[behavior.Property.Value]);
                            bhvele.AddXmlAttribute("起点", $"{behavior.From}");
                            bhvele.AddXmlAttribute("终点", $"{behavior.To}");

                            foreach (var point in behavior.KeyPoints)
                            {
                                var ptele = xmldoc.CreateElement("帧");
                                ptele.AddXmlAttribute("注释", "");
                                ptele.AddXmlAttribute("时间", point.Time);
                                ptele.AddXmlAttribute("值", $"{point.Value}");
                                ptele.AddXmlAttribute("表达式", point.Formula);

                                bhvele.AppendChild(ptele);
                            }

                        }
                        break;
                    case PPT.MsoAnimType.msoAnimTypeFilter:
                        {
                            var behavior = bhv as FilterBehaviorInformation;
                            bhvele.AddXmlAttribute("反转", behavior.Reveal);
                            bhvele.AddXmlAttribute("主滤镜", behavior.MainFilter);
                            bhvele.AddXmlAttribute("子滤镜", behavior.SubFilter);
                        }
                        break;
                    case PPT.MsoAnimType.msoAnimTypeSet:
                        {
                            var behavior = bhv as SetBehaviorInformation;
                            bhvele.AddXmlAttribute("属性类型", propdic1[behavior.Property.Value]);
                            bhvele.AddXmlAttribute("终点", $"{behavior.Value}");
                        }
                        break;
                    default:
                        break;
                }

                xmlele.AppendChild(bhvele);
            }

            return xmlele;
        }

        /// <summary>
        /// 录制原生效果。
        /// </summary>
        /// <param name="eff"></param>
        /// <param name="tags"></param>
        /// <returns></returns>
        public static XmlElement ExportNativeEffect(XmlDocument xmldoc, NativeEffectInformation eff)
        {
            var xmlele = xmldoc.CreateElement("原生动画效果"); // 创建元素

            xmlele.AddXmlAttribute("名称", eff.Name);
            xmlele.AddXmlAttribute("标签", string.Join(",", eff.Tags));
            xmlele.AddXmlAttribute("描述", eff.Note);

            SetTimeDetail(xmlele, eff);

            xmlele.AddXmlAttribute("类型", eff.AnimEffect);
            xmlele.AddXmlAttribute("退出", eff.Exit);
            xmlele.AddXmlAttribute("参数列表", string.Join(",", eff.Arguments));
            xmlele.AddXmlAttribute("文本模式", eff.TextUnitEffect);
            return xmlele;
        }


        #endregion

        #region 添加动画


        /// <summary>
        /// 为选中的图形集合对象添加动画。
        /// </summary>
        /// <param name="effectInformation"></param>
        /// <param name="animEffect"></param>
        public static void AddTargetAnimationOnSelectionShapeRange(EffectInformation effectInformation, NativeAnimEffect animEffect)
        {
            if (animEffect == null)
                animEffect = animtypedic2["自定义"];
            var slide = GetSlideInGeneralOccassion();
            var shapeRange = GetShapeRange();
            if (slide == null || shapeRange == null) return;
            var sequence = slide.TimeLine.MainSequence;
            if (effectInformation is ArtificialEffectInformation)
            {
                foreach (PPT.Shape shape in shapeRange)
                {
                    AddArtificialAnimationOnShape(sequence, shape, effectInformation as ArtificialEffectInformation, animEffect);
                }
            }
            else if (effectInformation is NativeEffectInformation)
            {
                foreach (PPT.Shape shape in shapeRange)
                {
                    AddNativeAnimationOnShape(sequence, shape, effectInformation as NativeEffectInformation);
                }
            }
            else if (effectInformation is GroupEffectInformation)
            {
                AddGroupAnimationOnShapeRange(sequence, shapeRange, effectInformation as GroupEffectInformation);
            }

            GlobalMessageStateUpdater.RaiseAnimationSequenceMessage();

        }

        /// <summary>
        /// 为指定图形对象集合添加动画。
        /// </summary>
        /// <param name="effectInformation"></param>
        public static void AddTargetAnimationOnSelectionShapeRange(EffectInformation effectInformation)
        {
            AddTargetAnimationOnSelectionShapeRange(effectInformation, null);

        }

        /// <summary>
        /// 组合动画
        /// </summary>
        /// <param name="sequence"></param>
        /// <param name="shaperange"></param>
        /// <param name="effInformation"></param>
        public static void AddGroupAnimationOnShapeRange(PPT.Sequence sequence, PPT.ShapeRange shaperange, GroupEffectInformation effInformation)
        {
            var shapelen = shaperange.Count;
            for (int i = 1; i <= shapelen; i += effInformation.TargetCount)
            {
                foreach (var eff in effInformation.EffectInformationList)
                {
                    var id = eff.Target + i - 1;

                    if (id > shapelen) continue;
                    var shp = shaperange[id];
                    if (eff is ArtificialEffectInformation)
                    {
                        AddArtificialAnimationOnShape(sequence, shp, eff as ArtificialEffectInformation, animtypedic2["自定义"]);
                    }
                    else if (eff is NativeEffectInformation)
                    {
                        AddNativeAnimationOnShape(sequence, shp, eff as NativeEffectInformation);
                    }
                    else if (eff is GroupEffectInformation)
                    {
                        AddGroupAnimationOnShapeRange(sequence, shaperange, eff as GroupEffectInformation);
                    }
                }
            }
        }

        /// <summary>
        /// 为指定图形添加人工动画。
        /// </summary>
        /// <param name="sequence">动画序列。</param>
        /// <param name="shape">图形。</param>
        /// <param name="effectInformation">想要添加的动画的具体信息。</param>
        /// <param name="animEffect">在 PPT 中显示的图标皮肤。</param>
        private static void AddArtificialAnimationOnShape(PPT.Sequence sequence, PPT.Shape shape, ArtificialEffectInformation effectInformation, NativeAnimEffect animEffect)
        {
            var animEffectType = animEffect.Item1;
            var isExit = animEffect.Item2;
            if (!isExit.HasValue)
                animEffectType = PPT.MsoAnimEffect.msoAnimEffectCustom;

            var eff = sequence.AddEffect(shape,
             animEffectType,
             PPT.MsoAnimateByLevel.msoAnimateLevelNone,
             PPT.MsoAnimTriggerType.msoAnimTriggerWithPrevious);

            var originCount = eff.Behaviors.Count;

            if (isExit.HasValue)
                eff.Exit = isExit.Value;

            if (effectInformation.Duration.HasValue)
                eff.Timing.Duration = effectInformation.Duration.Value;
            if (effectInformation.Delay.HasValue)
                eff.Timing.TriggerDelayTime = effectInformation.Delay.Value;
            if (effectInformation.Repeat.HasValue)
                eff.Timing.RepeatCount = effectInformation.Repeat.Value;
            if (effectInformation.SmoothStart.HasValue)
                eff.Timing.SmoothStart = effectInformation.SmoothStart.Value;
            if (effectInformation.SmoothEnd.HasValue)
                eff.Timing.SmoothEnd = effectInformation.SmoothEnd.Value;
            if (effectInformation.BounceEnd.HasValue)
                eff.Timing.BounceEnd = effectInformation.BounceEnd.Value;
            if (effectInformation.Accelerate.HasValue)
                eff.Timing.Accelerate = effectInformation.Accelerate.Value;
            if (effectInformation.Decelerate.HasValue)
                eff.Timing.Decelerate = effectInformation.Decelerate.Value;
            if (effectInformation.BounceEndIntensity.HasValue)
                eff.Timing.BounceEndIntensity = effectInformation.BounceEndIntensity.Value;
            if (effectInformation.AutoReverse.HasValue)
                eff.Timing.AutoReverse = effectInformation.AutoReverse.Value;

            foreach (var behaviorInformation in effectInformation.BehaviorInformationList)
            {
                AddBehaviorOnEffect(eff, behaviorInformation);
            }

            if (effectInformation.TextUnitEffect.HasValue)
                sequence.ConvertToTextUnitEffect(eff, effectInformation.TextUnitEffect.Value);

            for (int i = 0; i < originCount; i++)
            {
                eff.Behaviors[1].Delete();
            }

        }

        /// <summary>
        /// 为指定图形添加原生动画。
        /// </summary>
        /// <param name="sequence">动画序列。</param>
        /// <param name="shape">图形对象。</param>
        /// <param name="effectInformation">动画效果。</param>
        private static void AddNativeAnimationOnShape(PPT.Sequence sequence, PPT.Shape shape, NativeEffectInformation effectInformation)
        {
            var eff = sequence.AddEffect(shape,
             effectInformation.AnimEffect,
             PPT.MsoAnimateByLevel.msoAnimateLevelNone,
             PPT.MsoAnimTriggerType.msoAnimTriggerWithPrevious);

            if (effectInformation.Exit.HasValue)
                eff.Exit = effectInformation.Exit.Value;

            if (effectInformation.Duration.HasValue)
                eff.Timing.Duration = effectInformation.Duration.Value;
            if (effectInformation.Delay.HasValue)
                eff.Timing.TriggerDelayTime = effectInformation.Delay.Value;
            if (effectInformation.Repeat.HasValue)
                eff.Timing.RepeatCount = effectInformation.Repeat.Value;
            if (effectInformation.SmoothStart.HasValue)
                eff.Timing.SmoothStart = effectInformation.SmoothStart.Value;
            if (effectInformation.SmoothEnd.HasValue)
                eff.Timing.SmoothEnd = effectInformation.SmoothEnd.Value;
            if (effectInformation.BounceEnd.HasValue)
                eff.Timing.BounceEnd = effectInformation.BounceEnd.Value;
            if (effectInformation.Accelerate.HasValue)
                eff.Timing.Accelerate = effectInformation.Accelerate.Value;
            if (effectInformation.Decelerate.HasValue)
                eff.Timing.Decelerate = effectInformation.Decelerate.Value;
            if (effectInformation.BounceEndIntensity.HasValue)
                eff.Timing.BounceEndIntensity = effectInformation.BounceEndIntensity.Value;
            if (effectInformation.AutoReverse.HasValue)
                eff.Timing.AutoReverse = effectInformation.AutoReverse.Value;


            if (effectInformation.AnimEffect == PPT.MsoAnimEffect.msoAnimEffectSpin)
            {
                eff.Behaviors[1].RotationEffect.By = float.Parse(effectInformation.Arguments[0]);
            }
            else if (effectInformation.AnimEffect == PPT.MsoAnimEffect.msoAnimEffectGrowShrink)
            {
                eff.Behaviors[1].ScaleEffect.ByX = float.Parse(effectInformation.Arguments[0]);
                eff.Behaviors[1].ScaleEffect.ByY = float.Parse(effectInformation.Arguments[1]);
            }

            if (effectInformation.TextUnitEffect.HasValue)
                sequence.ConvertToTextUnitEffect(eff, effectInformation.TextUnitEffect.Value);
        }

        /// <summary>
        /// 为指定效果添加行为。
        /// </summary>
        /// <param name="effect"></param>
        /// <param name="behaviorInformation"></param>
        private static void AddBehaviorOnEffect(PPT.Effect effect, BehaviorInformation behaviorInformation)
        {
            var bhv = effect.Behaviors.Add(behaviorInformation.AnimType);
            if (behaviorInformation.Duration.HasValue)
                bhv.Timing.Duration = behaviorInformation.Duration.Value;
            if (behaviorInformation.Delay.HasValue)
                bhv.Timing.TriggerDelayTime = behaviorInformation.Delay.Value;
            if (behaviorInformation.Repeat.HasValue)
                bhv.Timing.RepeatCount = behaviorInformation.Repeat.Value;
            if (behaviorInformation.SmoothStart.HasValue)
                bhv.Timing.SmoothStart = behaviorInformation.SmoothStart.Value;
            if (behaviorInformation.SmoothEnd.HasValue)
                bhv.Timing.SmoothEnd = behaviorInformation.SmoothEnd.Value;
            if (behaviorInformation.BounceEnd.HasValue)
                bhv.Timing.BounceEnd = behaviorInformation.BounceEnd.Value;
            if (behaviorInformation.Accelerate.HasValue)
                bhv.Timing.Accelerate = behaviorInformation.Accelerate.Value;
            if (behaviorInformation.Decelerate.HasValue)
                bhv.Timing.Decelerate = behaviorInformation.Decelerate.Value;
            if (behaviorInformation.BounceEndIntensity.HasValue)
                bhv.Timing.BounceEndIntensity = behaviorInformation.BounceEndIntensity.Value;
            if (behaviorInformation.AutoReverse.HasValue)
                bhv.Timing.AutoReverse = behaviorInformation.AutoReverse.Value;

            switch (behaviorInformation.AnimType)
            {
                case PPT.MsoAnimType.msoAnimTypeSet:
                    {
                        var setinfo = behaviorInformation as SetBehaviorInformation;
                        var setprop = bhv.SetEffect;
                        if (setinfo.Property.HasValue)
                            setprop.Property = setinfo.Property.Value;

                        setprop.To = setinfo.Value;
                    }
                    break;
                case PPT.MsoAnimType.msoAnimTypeProperty:
                    {
                        var propinfo = behaviorInformation as PropertyBehaviorInformation;
                        var propprop = bhv.PropertyEffect;
                        if (propinfo.Property.HasValue)
                            propprop.Property = propinfo.Property.Value;

                        if (propinfo.From != null)
                            propprop.From = propinfo.From;
                        if (propinfo.To != null)
                            propprop.To = propinfo.To;

                        foreach (var pointInfomation in propinfo.KeyPoints)
                        {
                            var point = propprop.Points.Add();
                            point.Time = (float)pointInfomation.Time;
                            point.Value = pointInfomation.Value;
                            point.Formula = pointInfomation.Formula;
                        }

                    }
                    break;
                case PPT.MsoAnimType.msoAnimTypeColor:
                    {
                        throw new Exception("颜色相关处理暂时无效。");
                        var clrinfo = behaviorInformation as ColorBehaviorInformation;
                        var clrprop = bhv.ColorEffect;
                        if (clrinfo.From.HasValue)
                            clrprop.From.RGB = clrinfo.From.Value;
                        if (clrinfo.To.HasValue)
                            clrprop.To.RGB = clrinfo.To.Value;
                        if (clrinfo.By.HasValue)
                            clrprop.By.RGB = clrinfo.By.Value;
                    }
                    break;
                case PPT.MsoAnimType.msoAnimTypeScale:
                    {
                        var scinfo = behaviorInformation as ScaleBehaviorInformation;
                        var scprop = bhv.ScaleEffect;
                        if (scinfo.FromX.HasValue)
                            scprop.FromX = scinfo.FromX.Value;
                        if (scinfo.FromY.HasValue)
                            scprop.FromY = scinfo.FromY.Value;
                        if (scinfo.ToX.HasValue)
                            scprop.ToX = scinfo.ToX.Value;
                        if (scinfo.ToY.HasValue)
                            scprop.ToY = scinfo.ToY.Value;
                        if (scinfo.ByX.HasValue)
                            scprop.ByX = scinfo.ByX.Value;
                        if (scinfo.ByY.HasValue)
                            scprop.ByY = scinfo.ByY.Value;

                    }
                    break;
                case PPT.MsoAnimType.msoAnimTypeRotation:
                    {
                        var rotinfo = behaviorInformation as RotationBehaviorInformation;
                        var rotprop = bhv.RotationEffect;
                        if (rotinfo.From.HasValue)
                            rotprop.From = rotinfo.From.Value;
                        if (rotinfo.To.HasValue)
                            rotprop.To = rotinfo.To.Value;
                        if (rotinfo.By.HasValue)
                            rotprop.By = rotinfo.By.Value;
                    }
                    break;
                case PPT.MsoAnimType.msoAnimTypeFilter:
                    {
                        var ftinfo = behaviorInformation as FilterBehaviorInformation;
                        var ftprop = bhv.FilterEffect;
                        if (ftinfo.Reveal.HasValue)
                            ftprop.Reveal = ftinfo.Reveal.Value;
                        if (ftinfo.MainFilter.HasValue)
                            ftprop.Type = ftinfo.MainFilter.Value;
                        if (ftinfo.SubFilter.HasValue)
                            ftprop.Subtype = ftinfo.SubFilter.Value;
                        else
                            ftprop.Subtype = PPT.MsoAnimFilterEffectSubtype.msoAnimFilterEffectSubtypeInVertical;
                    }

                    break;
                case PPT.MsoAnimType.msoAnimTypeMotion:
                    {
                        var moinfo = behaviorInformation as MotionBehaviorInformation;
                        var moprop = bhv.MotionEffect;
                        if (moinfo.FromX.HasValue)
                            moprop.FromX = moinfo.FromX.Value;
                        if (moinfo.FromY.HasValue)
                            moprop.FromY = moinfo.FromY.Value;
                        if (moinfo.ToX.HasValue)
                            moprop.ToX = moinfo.ToX.Value;
                        if (moinfo.ToY.HasValue)
                            moprop.ToY = moinfo.ToY.Value;
                        if (moinfo.ByX.HasValue)
                            moprop.ByX = moinfo.ByX.Value;
                        if (moinfo.ByY.HasValue)
                            moprop.ByY = moinfo.ByY.Value;
                        if (moinfo.Path != null)
                            moprop.Path = moinfo.Path;

                    }
                    break;
                default:
                    break;
            }
        }
        #endregion

        #region 生成 VBA 代码

        /// <summary>
        /// 通过 Xml 数据生成 VBA 代码
        /// </summary>
        /// <param name="animEffect"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string CreateArtificialVBACode(XmlElement animEffect, string name)
        {
            StringBuilder sb = new StringBuilder();
            var 名称 = GetValidVBASubName(name);
            var 文本模式 = animEffect.GetAttribute("文本模式");
            var 时长 = animEffect.GetAttribute("时长");
            var 延迟 = animEffect.GetAttribute("延迟");
            var 重复 = GetRepeat(animEffect.GetAttribute("重复"));
            var 平滑 = animEffect.GetAttribute("平滑").Split(',');
            var 平滑1 = 平滑[0];
            var 平滑2 = 平滑[1];
            var 弹跳 = animEffect.GetAttribute("弹跳");
            var 加速 = animEffect.GetAttribute("加速");
            var 减速 = animEffect.GetAttribute("减速");
            var 弹跳速度 = animEffect.GetAttribute("弹跳速度");
            var 自动返回 = animEffect.GetAttribute("自动返回");
            sb.AppendLine("Sub " + 名称 + "()");
            sb.AppendLine("    Dim shp As Shape");
            sb.AppendLine("    Dim shprange As ShapeRange");
            sb.AppendLine("    Dim sld As Slide");
            sb.AppendLine("    Dim eff As Effect");
            sb.AppendLine("    Dim bhv As AnimationBehavior");
            sb.AppendLine("    Dim pt As AnimationPoint");
            sb.AppendLine("    Set shprange = Application.ActiveWindow.Selection.ShapeRange");
            sb.AppendLine("    Set sld = shprange.Parent");

            sb.AppendLine("    For Each shp In shprange");
            // sb.AppendLine("        shp.AnimationSettings.TextUnitEffect = " + 文本模式);
            sb.AppendLine("        Set eff = sld.TimeLine.MainSequence.AddEffect(shp, msoAnimEffectCustom, , msoAnimTriggerWithPrevious)");

            sb.AppendLine(时长.ToPrefix() + "        eff.Timing.Duration = " + 时长);
            sb.AppendLine(延迟.ToPrefix() + "        eff.Timing.TriggerDelayTime = " + 延迟);
            sb.AppendLine(重复.ToPrefix() + "        eff.Timing.RepeatCount = " + 重复);

            sb.AppendLine(平滑1.ToPrefix() + "        eff.Timing.SmoothStart = " + 平滑1);
            sb.AppendLine(平滑2.ToPrefix() + "        eff.Timing.SmoothEnd = " + 平滑2);
            sb.AppendLine(弹跳.ToPrefix() + "        eff.Timing.BounceEnd = " + 弹跳);

            sb.AppendLine(平滑1.ToSmoothPrefix() + "        eff.Timing.Accelerate = " + 加速);
            sb.AppendLine(平滑2.ToSmoothPrefix() + "        eff.Timing.Decelerate = " + 减速);
            sb.AppendLine(弹跳.ToSmoothPrefix() + "        eff.Timing.BounceEndIntensity = " + 弹跳速度);

            sb.AppendLine(自动返回.ToPrefix() + "        eff.Timing.AutoReverse = " + 自动返回);

            foreach (var behavior in animEffect.OfType<XmlElement>())
            {
                var b名称 = behavior.Name;
                var b时长 = behavior.GetAttribute("时长");
                var b延迟 = behavior.GetAttribute("延迟");
                var b重复 = GetRepeat(behavior.GetAttribute("重复"));
                var b平滑 = behavior.GetAttribute("平滑").Split(',');
                var b平滑1 = b平滑[0];
                var b平滑2 = b平滑[1];
                var b弹跳 = behavior.GetAttribute("弹跳");
                var b加速 = behavior.GetAttribute("加速");
                var b减速 = behavior.GetAttribute("减速");
                var b弹跳速度 = behavior.GetAttribute("弹跳速度");
                var b自动返回 = behavior.GetAttribute("自动返回");
                sb.AppendLine("\'        =======================================================");
                sb.AppendLine("        Set bhv = eff.Behaviors.Add(" + typedic2[b名称] + ")");
                sb.AppendLine(b时长.ToPrefix() + "        bhv.Timing.Duration = " + b时长);
                sb.AppendLine(b延迟.ToPrefix() + "        bhv.Timing.TriggerDelayTime = " + b延迟);
                sb.AppendLine(b重复.ToPrefix() + "        bhv.Timing.RepeatCount = " + b重复);

                sb.AppendLine(b平滑1.ToPrefix() + "        bhv.Timing.SmoothStart = " + b平滑1);
                sb.AppendLine(b平滑2.ToPrefix() + "        bhv.Timing.SmoothEnd = " + b平滑2);
                sb.AppendLine(b弹跳.ToPrefix() + "        bhv.Timing.BounceEnd = " + b弹跳);

                sb.AppendLine(b平滑1.ToSmoothPrefix() + "        bhv.Timing.Accelerate = " + b加速);
                sb.AppendLine(b平滑2.ToSmoothPrefix() + "        bhv.Timing.Decelerate = " + b减速);
                sb.AppendLine(b弹跳.ToSmoothPrefix() + "        bhv.Timing.BounceEndIntensity = " + b弹跳速度);

                sb.AppendLine(b自动返回.ToPrefix() + "        bhv.Timing.AutoReverse = " + b自动返回);
                sb.AppendLine();
                //sb.AppendLine("        bhv.Timing.Duration = " + b时长);
                //sb.AppendLine("        bhv.Timing.TriggerDelayTime = " + b延迟);
                //sb.AppendLine("        bhv.Timing.RepeatCount = " + b重复);

                switch (b名称)
                {
                    case "设置":
                        var set属性类型 = behavior.GetAttribute("属性类型");
                        var set属性值 = behavior.GetAttribute("属性值");
                        sb.AppendLine(set属性类型.ToPrefix() + "        bhv.SetEffect.Property = " + propdic2[set属性类型]);
                        sb.AppendLine(set属性值.ToPrefix() + "        bhv.SetEffect.To = " + set属性值);

                        break;
                    case "属性":
                        var prop属性类型 = behavior.GetAttribute("属性类型");
                        var prop属性值 = behavior.GetAttribute("属性值");
                        sb.AppendLine(prop属性类型.ToPrefix() + "        bhv.PropertyEffect.Property = " + propdic2[prop属性类型]);
                        sb.AppendLine(prop属性值.ToPrefix() + "        bhv.PropertyEffect.To = " + prop属性值);
                        foreach (var point in behavior.OfType<XmlElement>())
                        {
                            var pt时间 = point.GetAttribute("时间");
                            var pt值 = point.GetAttribute("值");
                            var pt表达式 = point.GetAttribute("表达式");
                            sb.AppendLine("        Set pt = bhv.PropertyEffect.Points.Add");
                            sb.AppendLine("        pt.Time = 0" + pt时间 + ": pt.Value = \"" + pt值 + "\": pt.Formula = \"" + pt表达式 + "\"");
                        }
                        break;
                    case "颜色":
                        var clr起点 = behavior.GetAttribute("起点");
                        var clr终点 = behavior.GetAttribute("终点");
                        var clr变化 = behavior.GetAttribute("变化");
                        sb.AppendLine(clr起点.ToPrefix() + "        bhv.ColorEffect.From.RGB = " + clr起点);
                        sb.AppendLine(clr终点.ToPrefix() + "        bhv.ColorEffect.To.RGB = " + clr终点);
                        //sb.AppendLine("        bhv.ColorEffect.By.RGB = " + clr变化);
                        break;
                    case "比例":
                        var sc起点 = behavior.GetAttribute("起点").Split(',');
                        var sc终点 = behavior.GetAttribute("终点").Split(',');
                        var sc变化 = behavior.GetAttribute("变化").Split(',');
                        sb.AppendLine(sc起点[0].ToPrefix() + "        bhv.ScaleEffect.FromX = " + sc起点[0]);
                        sb.AppendLine(sc起点[1].ToPrefix() + "        bhv.ScaleEffect.FromY = " + sc起点[1]);
                        sb.AppendLine(sc终点[0].ToPrefix() + "        bhv.ScaleEffect.ToX = " + sc终点[0]);
                        sb.AppendLine(sc终点[1].ToPrefix() + "        bhv.ScaleEffect.ToY = " + sc终点[1]);
                        //sb.AppendLine("        bhv.ScaleEffect.ByX = " + sc变化[0]);
                        //sb.AppendLine("        bhv.ScaleEffect.ByY = " + sc变化[1]);
                        break;
                    case "旋转":
                        var rot起点 = behavior.GetAttribute("起点");
                        var rot终点 = behavior.GetAttribute("终点");
                        var rot变化 = behavior.GetAttribute("变化");
                        sb.AppendLine(rot起点.ToPrefix() + "        bhv.RotationEffect.From = " + rot起点);
                        sb.AppendLine(rot终点.ToPrefix() + "        bhv.RotationEffect.To = " + rot终点);
                        //sb.AppendLine("        bhv.RotationEffect.From = " + "0");
                        //sb.AppendLine("        bhv.RotationEffect.To = " + rot变化);
                        //sb.AppendLine("        bhv.RotationEffect.By = " + rot变化);
                        break;
                    case "滤镜":
                        var ft主滤镜 = behavior.GetAttribute("主滤镜");
                        var ft子滤镜 = behavior.GetAttribute("子滤镜");
                        var ft反转 = behavior.GetAttribute("反转");
                        sb.AppendLine(ft反转.ToPrefix() + "        bhv.FilterEffect.Reveal = " + ft反转);
                        sb.AppendLine(ft主滤镜.ToPrefix() + "         bhv.FilterEffect.Type = " + ft主滤镜);
                        if (ft子滤镜 != "none")
                            sb.AppendLine("         bhv.FilterEffect.Subtype = " + ft子滤镜);
                        else
                            sb.AppendLine("         bhv.FilterEffect.Subtype = 1");

                        break;
                    case "移动":
                        var mo起点 = behavior.GetAttribute("起点").Split(',');
                        var mo终点 = behavior.GetAttribute("终点").Split(',');
                        var mo变化 = behavior.GetAttribute("变化").Split(',');
                        var mo路径 = behavior.GetAttribute("路径");
                        sb.AppendLine(mo起点[0].ToPrefix() + "        bhv.MotionEffect.FromX = " + mo起点[0]);
                        sb.AppendLine(mo起点[1].ToPrefix() + "        bhv.MotionEffect.FromY = " + mo起点[1]);
                        sb.AppendLine(mo终点[0].ToPrefix() + "        bhv.MotionEffect.ToX = " + mo终点[0]);
                        sb.AppendLine(mo终点[1].ToPrefix() + "        bhv.MotionEffect.ToY = " + mo终点[1]);
                        //sb.AppendLine("        bhv.MotionEffect.ByX = " + mo变化[0]);
                        //sb.AppendLine("        bhv.MotionEffect.ByY = " + mo变化[1]);
                        sb.AppendLine(mo路径.ToPrefix() + "        bhv.MotionEffect.Path = \"" + mo路径 + "\"");
                        sb.AppendLine("    sld.TimeLine.MainSequence.ConvertToTextUnitEffect eff, " + 文本模式);
                        break;
                    default:
                        break;
                }

            }
            sb.AppendLine("\'        =======================================================");
            sb.AppendLine("        eff.Behaviors(1).Delete");
            sb.AppendLine("    sld.TimeLine.MainSequence.ConvertToTextUnitEffect eff, " + 文本模式);
            sb.AppendLine("    Next");

            sb.AppendLine("End Sub");
            sb.AppendLine();
            return sb.ToString();
        }

        /// <summary>
        /// 通过 Xml 数据生成 VBA 代码
        /// </summary>
        /// <param name="animEffect"></param>
        /// <param name="name"></param>
        /// <returns></returns>
        public static string CreateNativeVBACode(XmlElement animEffect, string name)
        {
            StringBuilder sb = new StringBuilder();

            var 名称 = GetValidVBASubName(name);
            var 文本模式 = animEffect.GetAttribute("文本模式");
            var 时长 = animEffect.GetAttribute("时长");
            var 延迟 = animEffect.GetAttribute("延迟");
            var 重复 = GetRepeat(animEffect.GetAttribute("重复"));
            var 平滑 = animEffect.GetAttribute("平滑").Split(',');
            var 平滑1 = 平滑[0];
            var 平滑2 = 平滑[1];
            var 弹跳 = animEffect.GetAttribute("弹跳");
            var 加速 = animEffect.GetAttribute("加速");
            var 减速 = animEffect.GetAttribute("减速");
            var 弹跳速度 = animEffect.GetAttribute("弹跳速度");
            var 自动返回 = animEffect.GetAttribute("自动返回");
            var 类型 = animEffect.GetAttribute("类型");
            var 退出 = animEffect.GetAttribute("退出");
            var 参数列表 = animEffect.GetAttribute("参数列表").Split(',');
            var pptAnimType = StringToPPTAnimType(类型);
            sb.AppendLine("Sub " + 名称 + "()");
            sb.AppendLine("    Dim shp As Shape");
            sb.AppendLine("    Dim shprange As ShapeRange");
            sb.AppendLine("    Dim sld As Slide");
            sb.AppendLine("    Dim eff As Effect");
            sb.AppendLine("    Dim bhv As AnimationBehavior");
            sb.AppendLine("    Dim pt As AnimationPoint");
            sb.AppendLine("    Set shprange = Application.ActiveWindow.Selection.ShapeRange");
            sb.AppendLine("    Set sld = shprange.Parent");

            sb.AppendLine("    For Each shp In shprange");
            //sb.AppendLine("        shp.AnimationSettings.TextUnitEffect = "+ 文本模式);

            sb.AppendLine("        Set eff = sld.TimeLine.MainSequence.AddEffect(shp, " + 类型 + ", , msoAnimTriggerWithPrevious)");


            sb.AppendLine(类型.ToAppearPrefix() + "        eff.Exit = " + 退出);

            sb.AppendLine(时长.ToPrefix() + "        eff.Timing.Duration = " + 时长);
            sb.AppendLine(延迟.ToPrefix() + "        eff.Timing.TriggerDelayTime = " + 延迟);
            sb.AppendLine(重复.ToPrefix() + "        eff.Timing.RepeatCount = " + 重复);

            sb.AppendLine(平滑1.ToPrefix() + "        eff.Timing.SmoothStart = " + 平滑1);
            sb.AppendLine(平滑2.ToPrefix() + "        eff.Timing.SmoothEnd = " + 平滑2);
            sb.AppendLine(弹跳.ToPrefix() + "        eff.Timing.BounceEnd = " + 弹跳);

            sb.AppendLine(平滑1.ToSmoothPrefix() + "        eff.Timing.Accelerate = " + 加速);
            sb.AppendLine(平滑2.ToSmoothPrefix() + "        eff.Timing.Decelerate = " + 减速);
            sb.AppendLine(弹跳.ToSmoothPrefix() + "        eff.Timing.BounceEndIntensity = " + 弹跳速度);

            sb.AppendLine(自动返回.ToPrefix() + "        eff.Timing.AutoReverse = " + 自动返回);

            if (pptAnimType == PPT.MsoAnimEffect.msoAnimEffectGrowShrink)
            {
                sb.AppendLine(String.Format(Properties.Resources.DetailAnimVBA_Large, 参数列表));
            }
            else if (pptAnimType == PPT.MsoAnimEffect.msoAnimEffectSpin)
            {
                sb.AppendLine(String.Format(Properties.Resources.DetailAnimVBA_Spin, 参数列表));
            }
            else if ((int)pptAnimType >= (int)PPT.MsoAnimEffect.msoAnimEffectPathCircle)
            {
                sb.AppendLine(String.Format(Properties.Resources.DetailAnimVBA_Path, 参数列表));
            }
            sb.AppendLine("    sld.TimeLine.MainSequence.ConvertToTextUnitEffect eff, " + 文本模式);



            sb.AppendLine("    Next");
            sb.AppendLine("End Sub");
            sb.AppendLine();
            return sb.ToString();
        }

        /// <summary>
        /// 通过内存数据生成 VBA 代码
        /// </summary>
        /// <param name="animEffect"></param>
        /// <returns></returns>
        public static string CreateArtificialVBACode(ArtificialEffectInformation animEffect)
        {
            StringBuilder sb = new StringBuilder();
            var 名称 = animEffect.Name;
            var 文本模式 = animEffect.TextUnitEffect;
            var 时长 = animEffect.Duration;
            var 延迟 = animEffect.Delay;
            var 重复 = animEffect.Repeat;
            var 平滑1 = animEffect.SmoothStart;
            var 平滑2 = animEffect.SmoothEnd;
            var 弹跳 = animEffect.BounceEnd;
            var 加速 = animEffect.Accelerate;
            var 减速 = animEffect.Decelerate;
            var 弹跳速度 = animEffect.BounceEndIntensity;
            var 自动返回 = animEffect.AutoReverse;
            sb.AppendLine("Sub " + 名称 + "()");
            sb.AppendLine("    Dim shp As Shape");
            sb.AppendLine("    Dim shprange As ShapeRange");
            sb.AppendLine("    Dim sld As Slide");
            sb.AppendLine("    Dim eff As Effect");
            sb.AppendLine("    Dim bhv As AnimationBehavior");
            sb.AppendLine("    Dim pt As AnimationPoint");
            sb.AppendLine("    Set shprange = Application.ActiveWindow.Selection.ShapeRange");
            sb.AppendLine("    Set sld = shprange.Parent");

            sb.AppendLine("    For Each shp In shprange");
            // sb.AppendLine("        shp.AnimationSettings.TextUnitEffect = " + 文本模式);
            sb.AppendLine("        Set eff = sld.TimeLine.MainSequence.AddEffect(shp, msoAnimEffectCustom, , msoAnimTriggerWithPrevious)");

            sb.AppendLine(时长.ToPrefix() + "        eff.Timing.Duration = " + 时长);
            sb.AppendLine(延迟.ToPrefix() + "        eff.Timing.TriggerDelayTime = " + 延迟);
            sb.AppendLine(重复.ToPrefix() + "        eff.Timing.RepeatCount = " + 重复);

            sb.AppendLine(平滑1.ToPrefix() + "        eff.Timing.SmoothStart = " + 平滑1);
            sb.AppendLine(平滑2.ToPrefix() + "        eff.Timing.SmoothEnd = " + 平滑2);
            sb.AppendLine(弹跳.ToPrefix() + "        eff.Timing.BounceEnd = " + 弹跳);

            sb.AppendLine(平滑1.ToSmoothPrefix() + "        eff.Timing.Accelerate = " + 加速);
            sb.AppendLine(平滑2.ToSmoothPrefix() + "        eff.Timing.Decelerate = " + 减速);
            sb.AppendLine(弹跳.ToSmoothPrefix() + "        eff.Timing.BounceEndIntensity = " + 弹跳速度);

            sb.AppendLine(自动返回.ToPrefix() + "        eff.Timing.AutoReverse = " + 自动返回);

            foreach (var behavior in animEffect.BehaviorInformationList)
            {
                var b名称 = behavior.AnimType;
                var b时长 = behavior.Duration;
                var b延迟 = behavior.Delay;
                var b重复 = behavior.Repeat;
                var b平滑1 = behavior.SmoothStart;
                var b平滑2 = behavior.SmoothEnd;
                var b弹跳 = behavior.BounceEnd;
                var b加速 = behavior.Accelerate;
                var b减速 = behavior.Decelerate;
                var b弹跳速度 = behavior.BounceEndIntensity;
                var b自动返回 = behavior.AutoReverse;
                sb.AppendLine("\'        =======================================================");
                sb.AppendLine("        Set bhv = eff.Behaviors.Add(" + b名称 + ")");
                sb.AppendLine(b时长.ToPrefix() + "        bhv.Timing.Duration = " + b时长);
                sb.AppendLine(b延迟.ToPrefix() + "        bhv.Timing.TriggerDelayTime = " + b延迟);
                sb.AppendLine(b重复.ToPrefix() + "        bhv.Timing.RepeatCount = " + b重复);

                sb.AppendLine(b平滑1.ToPrefix() + "        bhv.Timing.SmoothStart = " + b平滑1);
                sb.AppendLine(b平滑2.ToPrefix() + "        bhv.Timing.SmoothEnd = " + b平滑2);
                sb.AppendLine(b弹跳.ToPrefix() + "        bhv.Timing.BounceEnd = " + b弹跳);

                sb.AppendLine(b平滑1.ToSmoothPrefix() + "        bhv.Timing.Accelerate = " + b加速);
                sb.AppendLine(b平滑2.ToSmoothPrefix() + "        bhv.Timing.Decelerate = " + b减速);
                sb.AppendLine(b弹跳.ToSmoothPrefix() + "        bhv.Timing.BounceEndIntensity = " + b弹跳速度);

                sb.AppendLine(b自动返回.ToPrefix() + "        bhv.Timing.AutoReverse = " + b自动返回);
                sb.AppendLine();
                //sb.AppendLine("        bhv.Timing.Duration = " + b时长);
                //sb.AppendLine("        bhv.Timing.TriggerDelayTime = " + b延迟);
                //sb.AppendLine("        bhv.Timing.RepeatCount = " + b重复);

                switch (b名称)
                {
                    case PPT.MsoAnimType.msoAnimTypeSet:
                        var setbhv = behavior as SetBehaviorInformation;
                        var set属性类型 = setbhv.Property;
                        var set属性值 = setbhv.Value;
                        sb.AppendLine(set属性类型.ToPrefix() + "        bhv.SetEffect.Property = " + set属性类型);
                        sb.AppendLine("        bhv.SetEffect.To = " + set属性值);

                        break;
                    case PPT.MsoAnimType.msoAnimTypeProperty:
                        var propbhv = behavior as PropertyBehaviorInformation;
                        var prop属性类型 = propbhv.Property;
                        var prop属性起点 = propbhv.From;
                        var prop属性终点 = propbhv.To;
                        sb.AppendLine(prop属性类型.ToPrefix() + "        bhv.PropertyEffect.Property = " + prop属性类型);
                        sb.AppendLine((prop属性起点 == null ? "\'" : "") + "        bhv.PropertyEffect.From = " + prop属性起点);
                        sb.AppendLine((prop属性终点 == null ? "\'" : "") + "        bhv.PropertyEffect.To = " + prop属性终点);
                        foreach (var point in propbhv.KeyPoints)
                        {
                            var pt时间 = point.Time;
                            var pt值 = point.Value;
                            var pt表达式 = point.Formula;
                            sb.AppendLine("        Set pt = bhv.PropertyEffect.Points.Add");
                            sb.AppendLine("        pt.Time = 0" + pt时间 + ": pt.Value = \"" + pt值 + "\": pt.Formula = \"" + pt表达式 + "\"");

                        }
                        break;
                    case PPT.MsoAnimType.msoAnimTypeColor:
                        var clrbhv = behavior as ColorBehaviorInformation;
                        var clr起点 = clrbhv.From;
                        var clr终点 = clrbhv.To;
                        var clr变化 = clrbhv.By;
                        sb.AppendLine(clr起点.ToPrefix() + "        bhv.ColorEffect.From.RGB = " + clr起点);
                        sb.AppendLine(clr终点.ToPrefix() + "        bhv.ColorEffect.To.RGB = " + clr终点);
                        //sb.AppendLine("        bhv.ColorEffect.By.RGB = " + clr变化);
                        break;
                    case PPT.MsoAnimType.msoAnimTypeScale:
                        var scbhv = behavior as ScaleBehaviorInformation;

                        sb.AppendLine(scbhv.FromX.ToPrefix() + "        bhv.ScaleEffect.FromX = " + scbhv.FromX);
                        sb.AppendLine(scbhv.FromY.ToPrefix() + "        bhv.ScaleEffect.FromY = " + scbhv.FromY);
                        sb.AppendLine(scbhv.ToX.ToPrefix() + "        bhv.ScaleEffect.ToX = " + scbhv.ToX);
                        sb.AppendLine(scbhv.ToY.ToPrefix() + "        bhv.ScaleEffect.ToY = " + scbhv.ToY);
                        //sb.AppendLine("        bhv.ScaleEffect.ByX = " + sc变化[0]);
                        //sb.AppendLine("        bhv.ScaleEffect.ByY = " + sc变化[1]);
                        break;
                    case PPT.MsoAnimType.msoAnimTypeRotation:
                        var rotbhv = behavior as RotationBehaviorInformation;

                        var rot起点 = rotbhv.From;
                        var rot终点 = rotbhv.To;
                        var rot变化 = rotbhv.By;
                        sb.AppendLine(rot起点.ToPrefix() + "        bhv.RotationEffect.From = " + rot起点);
                        sb.AppendLine(rot终点.ToPrefix() + "        bhv.RotationEffect.To = " + rot终点);
                        //sb.AppendLine("        bhv.RotationEffect.From = " + "0");
                        //sb.AppendLine("        bhv.RotationEffect.To = " + rot变化);
                        //sb.AppendLine("        bhv.RotationEffect.By = " + rot变化);
                        break;
                    case PPT.MsoAnimType.msoAnimTypeFilter:
                        var ftbhv = behavior as FilterBehaviorInformation;
                        var ft主滤镜 = ftbhv.MainFilter;
                        var ft子滤镜 = ftbhv.SubFilter;
                        var ft反转 = ftbhv.Reveal;
                        sb.AppendLine(ft反转.ToPrefix() + "        bhv.FilterEffect.Reveal = " + ft反转);
                        sb.AppendLine(ft主滤镜.ToPrefix() + "         bhv.FilterEffect.Type = " + ft主滤镜);
                        sb.AppendLine(ft子滤镜.ToPrefix() + "         bhv.FilterEffect.Subtype = " + ft子滤镜);

                        break;
                    case PPT.MsoAnimType.msoAnimTypeMotion:
                        var mobhv = behavior as MotionBehaviorInformation;

                        sb.AppendLine(mobhv.FromX.ToPrefix() + "        bhv.MotionEffect.FromX = " + mobhv.FromX);
                        sb.AppendLine(mobhv.FromY.ToPrefix() + "        bhv.MotionEffect.FromY = " + mobhv.FromY);
                        sb.AppendLine(mobhv.ToX.ToPrefix() + "        bhv.MotionEffect.ToX = " + mobhv.ToX);
                        sb.AppendLine(mobhv.ToY.ToPrefix() + "        bhv.MotionEffect.ToY = " + mobhv.ToY);
                        //sb.AppendLine("        bhv.MotionEffect.ByX = " + mo变化[0]);
                        //sb.AppendLine("        bhv.MotionEffect.ByY = " + mo变化[1]);
                        sb.AppendLine(mobhv.Path.ToPrefix() + "        bhv.MotionEffect.Path = \"" + mobhv.Path + "\"");
                        sb.AppendLine("    sld.TimeLine.MainSequence.ConvertToTextUnitEffect eff, " + 文本模式);
                        break;
                    default:
                        break;
                }

            }
            sb.AppendLine("\'        =======================================================");
            sb.AppendLine("        eff.Behaviors(1).Delete");
            sb.AppendLine("    sld.TimeLine.MainSequence.ConvertToTextUnitEffect eff, " + 文本模式);
            sb.AppendLine("    Next");

            sb.AppendLine("End Sub");
            sb.AppendLine();
            return sb.ToString();
        }

        /// <summary>
        /// 通过内存数据生成 VBA 代码
        /// </summary>
        /// <param name="animEffect"></param>
        /// <returns></returns>
        public static string CreateNativeVBACode(NativeEffectInformation animEffect)
        {
            StringBuilder sb = new StringBuilder();
            var 名称 = animEffect.Name;
            var 文本模式 = animEffect.TextUnitEffect;
            var 时长 = animEffect.Duration;
            var 延迟 = animEffect.Delay;
            var 重复 = animEffect.Repeat;
            var 平滑1 = animEffect.SmoothStart;
            var 平滑2 = animEffect.SmoothEnd;
            var 弹跳 = animEffect.BounceEnd;
            var 加速 = animEffect.Accelerate;
            var 减速 = animEffect.Decelerate;
            var 弹跳速度 = animEffect.BounceEndIntensity;
            var 自动返回 = animEffect.AutoReverse;

            var 类型 = animEffect.AnimEffect;
            var 退出 = animEffect.Exit;
            var 参数列表 = animEffect.Arguments;

            sb.AppendLine("Sub " + 名称 + "()");
            sb.AppendLine("    Dim shp As Shape");
            sb.AppendLine("    Dim shprange As ShapeRange");
            sb.AppendLine("    Dim sld As Slide");
            sb.AppendLine("    Dim eff As Effect");
            sb.AppendLine("    Dim bhv As AnimationBehavior");
            sb.AppendLine("    Dim pt As AnimationPoint");
            sb.AppendLine("    Set shprange = Application.ActiveWindow.Selection.ShapeRange");
            sb.AppendLine("    Set sld = shprange.Parent");

            sb.AppendLine("    For Each shp In shprange");
            //sb.AppendLine("        shp.AnimationSettings.TextUnitEffect = "+ 文本模式);

            sb.AppendLine("        Set eff = sld.TimeLine.MainSequence.AddEffect(shp, " + 类型 + ", , msoAnimTriggerWithPrevious)");


            sb.AppendLine(类型.ToAppearPrefix() + "        eff.Exit = " + 退出);

            sb.AppendLine(时长.ToPrefix() + "        eff.Timing.Duration = " + 时长);
            sb.AppendLine(延迟.ToPrefix() + "        eff.Timing.TriggerDelayTime = " + 延迟);
            sb.AppendLine(重复.ToPrefix() + "        eff.Timing.RepeatCount = " + 重复);

            sb.AppendLine(平滑1.ToPrefix() + "        eff.Timing.SmoothStart = " + 平滑1);
            sb.AppendLine(平滑2.ToPrefix() + "        eff.Timing.SmoothEnd = " + 平滑2);
            sb.AppendLine(弹跳.ToPrefix() + "        eff.Timing.BounceEnd = " + 弹跳);

            sb.AppendLine(平滑1.ToSmoothPrefix() + "        eff.Timing.Accelerate = " + 加速);
            sb.AppendLine(平滑2.ToSmoothPrefix() + "        eff.Timing.Decelerate = " + 减速);
            sb.AppendLine(弹跳.ToSmoothPrefix() + "        eff.Timing.BounceEndIntensity = " + 弹跳速度);

            sb.AppendLine(自动返回.ToPrefix() + "        eff.Timing.AutoReverse = " + 自动返回);


            if (类型 == PPT.MsoAnimEffect.msoAnimEffectGrowShrink)
            {
                sb.AppendLine(String.Format(Properties.Resources.DetailAnimVBA_Large, 参数列表));
            }
            else if (类型 == PPT.MsoAnimEffect.msoAnimEffectSpin)
            {
                sb.AppendLine(String.Format(Properties.Resources.DetailAnimVBA_Spin, 参数列表));
            }
            else if ((int)类型 >= (int)PPT.MsoAnimEffect.msoAnimEffectPathCircle)
            {
                sb.AppendLine(String.Format(Properties.Resources.DetailAnimVBA_Path, 参数列表));
            }
            sb.AppendLine("    sld.TimeLine.MainSequence.ConvertToTextUnitEffect eff, " + 文本模式);



            sb.AppendLine("    Next");
            sb.AppendLine("End Sub");
            sb.AppendLine();
            return sb.ToString();
        }



        #endregion
    }
}
